#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

import os.path
import shutil
import time

from common.const import ReportDBLabel, DBLogLevel
from common.parse_parafile import ParamFileUtil
from exchange import log
from exchange.commons.common import get_databases, get_key_value, convert_byte_to_mb, get_percentage_data
from exchange.commons.const import ExchangeJobInfo, BodyErr
from exchange.commons.exchange_exception import ExchangeErrCodeException, ExchangeInternalException
from exchange.commons.exchange_function_tool import log_start_end, out_result_with_job_info, \
    progress_notify_with_job_info
from exchange.commons.exchange_param_parse import ExchangeParamParse
from common.common_models import LogDetail


# Exchange备份前置任务基类
class ExchangeBackupPrePare:
    def __init__(self, pid):
        self._pid = pid
        self._param = ParamFileUtil.parse_param_file(pid)

    def check_disk_capacity(self, disk):
        try:
            disk = disk.split(":")[0][-1]
            total_capacity, _, free_capacity = shutil.disk_usage(f"{disk}:")
        except Exception as err:
            error_message = f"Write progress file failed exception: {err}, " \
                            f"Disk path: {disk}, Error getting disk remaining space"
            log.error(error_message)
            raise ExchangeInternalException(error_message) from err
        log.info("Calculation of remaining disk space successful!")
        percent = ExchangeParamParse.get_available_capacity_threshold(self._param)
        free_mb = convert_byte_to_mb(free_capacity)
        need_mb = get_percentage_data(convert_byte_to_mb(total_capacity), percent)
        log.info(f'Free disk space: {free_mb}MB, backup need space: {need_mb}MB.')
        # 单机/DAG/数据库备份时需要预留空间打快照, 默认磁盘总量的5%
        if free_mb < need_mb:
            raise ExchangeErrCodeException(log_detail=LogDetail(logInfo=ReportDBLabel.PRE_REQUISIT_FAILED,
                                                                logDetail=BodyErr.EXCHANGE_NO_DISK_SPACE.value,
                                                                logDetailParam=[disk, str(need_mb)],
                                                                logTimestamp=int(time.time()),
                                                                logLevel=DBLogLevel.ERROR))

    @log_start_end()
    @out_result_with_job_info()
    @progress_notify_with_job_info()
    def do_prepare_task(self, job_info: ExchangeJobInfo):
        # 前置任务上个副本清理残留数据
        self.clean_last_copy_data()
        flags, m_username = get_key_value(f'job_protectEnv_auth_authKey_{job_info.pid}')
        flags, m_password = get_key_value(f'job_protectEnv_auth_authPwd_{job_info.pid}')
        db_list, drive_letter, guids = get_databases(m_username, m_password)
        for disk in drive_letter:
            self.check_disk_capacity(disk)
        return True

    def clean_last_copy_data(self):
        meta_path = ExchangeParamParse.get_meta_path(self._param)
        # 清理 sqlite文件
        sqlite_path = os.path.join(meta_path, "sqlite")
        if os.path.exists(sqlite_path):
            shutil.rmtree(sqlite_path)
            log.info(f"clean {sqlite_path} success!")
        # 删除meta仓下的db_name.meta文件
        for filename in os.listdir(meta_path):
            if filename.endswith(".meta"):
                file_path = os.path.join(meta_path, filename)
                os.remove(file_path)
                log.info(f"clean {file_path} success!")

    def get_job_info(self):
        job_info = ExchangeJobInfo(pid=self._pid,
                                   job_id=ExchangeParamParse.get_job_id(self._param),
                                   sub_job_id=ExchangeParamParse.get_sub_job_id(self._param),
                                   copy_id=ExchangeParamParse.get_copy_id(self._param),
                                   backup_type=ExchangeParamParse.get_type(self._param),
                                   meta_path=ExchangeParamParse.get_meta_path(self._param),
                                   data_reps=ExchangeParamParse.get_data_reps(self._param),
                                   cache_path=ExchangeParamParse.get_cache_path(self._param),
                                   backup_result=ExchangeParamParse.get_backup_result(self._param))
        return job_info
